
var TestLoSMapBase = cc.Layer.extend({
    ctor:function () {
        this._super();
        this._initData();
        this._initBackgroud();
        this._initFloatingMenu();
        this._initMainLayer();
        this._initRobot();
        this._initLoSComponentRender();
        this._initKeyboard();
        this._initDebugDraw();
        this._initLoSMask();
        //
        this._losMaskNode.addTarget(this._robotObject, this._robotObject.getLoSComponentCore);
        this.disableSightRange();
        this.scheduleUpdate();
    },
    _initData:function() {
        this._isDirtyDetectionOn = false;
        this._isForceLoSUpdate = false;
        this._shadows = [];
    },
    _initBackgroud:function() {
        this._backgroudLayer = new cc.LayerColor(cc.color(28, 28, 88, 255), cc.winSize.width, cc.winSize.height);
        this.addChild(this._backgroudLayer, -1);
    },
    _initFloatingMenu:function() {
        cc.MenuItemFont.setFontSize(cc.sys.isNative ? 20 : 14);
        this._floatingMenu = new ssr.ScrollPanel(cc.color(0, 0, 0, 150), cc.winSize.width * 0.25, cc.winSize.height * 0.8);
        this._floatingMenu.setPosition(cc.winSize.width * 0.5, cc.winSize.height * 0.5);
        this._floatingMenu.hideLeft();
        this._floatingMenu.setItemAlignment(ssr.ScrollPanel.ITEM_ALIGNMENT_LEFT);

        this._debugTextPanelItem = new ssr.TextPanelItem(
            "  --- Render ---",
            cc.sys.isNative ? cc.MenuItemFont.getFontName(): cc.MenuItemFont.fontName(), 
            cc.sys.isNative ? cc.MenuItemFont.getFontSize(): cc.MenuItemFont.fontSize()
        );
        this._losSelfCullingMenuPanelItem = new ssr.ToggleMenuPanelItem(
            [
                "  × Self Culling", 
                "  ○ Self Culling"
            ], this._losSelfCullingMenuCallback, this
        );
        this._losMaskRenderMenuPanelItem = new ssr.ToggleMenuPanelItem(
            [
                "  × Mask", 
                "  ○ Mask"
            ], this._losMaskRenderMenuCallback, this
        );
        this._losShadowRenderMenuPanelItem = new ssr.ToggleMenuPanelItem(
            [
                "  × Shadow", 
                "  ○ Shadow"
            ], this._losShadowRenderMenuCallback, this
        );
        this._losShadowDynamicRenderMenuPanelItem = new ssr.ToggleMenuPanelItem(
            [
                "  × Dynamic", 
                "  ○ Dynamic"
            ], this._losShadowDynamicRenderMenuCallback, this
        );
        this._losShadowTextureRenderMenuPanelItem = new ssr.ToggleMenuPanelItem(
            [
                "  × Texture", 
                "  ○ Texture"
            ], this._losShadowTextureRenderMenuCallback, this
        );
        this._losShadowRadiusPlusMenuPanelItem = new ssr.MenuPanelItem(
            "  Shadow Range+", 
            this._shadowRangePlusMenuCallback, this
        );
        this._losShadowRadiusMinusMenuPanelItem = new ssr.MenuPanelItem(
            "  Shadow Range-", 
            this._shadowRangeMinusMenuCallback, this
        );
        this._sightAreaRenderMenuPanelItem = new ssr.ToggleMenuPanelItem(
            [
                "  × Sight Area",
                "  ○ Sight Area" 
            ], this._sightAreaRenderMenuCallback, this
        );
        this._sightLightRenderMenuPanelItem = new ssr.ToggleMenuPanelItem(
            [
                "  × Sight Light",
                "  ○ Sight Light" 
            ], this._sightLightRenderMenuCallback, this
        );
        this._sightRangeRenderMenuPanelItem = new ssr.ToggleMenuPanelItem(
            [
                "  × Range", 
                "  ○ Range"
            ], this._sightRangeRenderMenuCallback, this
        );
        this._rayRenderMenuPanelItem = new ssr.ToggleMenuPanelItem(
            [
                "  × Ray", 
                "  ○ Ray"
            ], this._rayRenderMenuCallback, this
        );
        this._hitPointRenderMenuPanelItem = new ssr.ToggleMenuPanelItem(
            [
                "  × HitPoint", 
                "  ○ HitPoint"
            ], this._hitPointRenderMenuCallback, this
        );
        this._sightVertRenderMenuPanelItem = new ssr.ToggleMenuPanelItem(
            [
                "  × SightVert", 
                "  ○ SightVert"
            ], this._sightVertRenderMenuCallback, this
        );
        this._potentialBlockingEdgesRenderMenuPanelItem = new ssr.ToggleMenuPanelItem(
            [
                "  × PotentialEdge", 
                "  ○ PotentialEdge"
            ], this._potentialBlockingEdgesRenderMenuCallback, this
        );
        this._blockingEdgesRenderMenuPanelItem = new ssr.ToggleMenuPanelItem(
            [
                "  × BlockingEdge", 
                "  ○ BlockingEdge"
            ], this._blockingEdgesRenderMenuCallback, this
        );
        this._visibleEdgeRenderMenuPanelItem = new ssr.ToggleMenuPanelItem(
            [
                "  × VisibleEdge",
                "  ○ VisibleEdge" 
            ], this._visibleEdgeRenderMenuCallback, this
        );
        this._sightRangeMenuPanelItem = new ssr.ToggleMenuPanelItem(
            [
                "  × Sight Range", 
                "  ○ Sight Range"
            ], this._sightRangeMenuCallback, this
        );
        this._losConfigTextPanelItem = new ssr.TextPanelItem(
            "  --- LoS Config ---",
            cc.sys.isNative ? cc.MenuItemFont.getFontName(): cc.MenuItemFont.fontName(), 
            cc.sys.isNative ? cc.MenuItemFont.getFontSize(): cc.MenuItemFont.fontSize()
        );
        this._sightRangePlusMenuPanelItem = new ssr.MenuPanelItem(
            "  Sight Range+", 
            this._sightRangePlusMenuCallback, this
        );
        this._sightRangeMinusMenuPanelItem = new ssr.MenuPanelItem(
            "  Sight Range-", 
            this._sightRangeMinusMenuCallback, this
        );
        this._sightAnglePlusMenuPanelItem = new ssr.MenuPanelItem(
            "  Angle+", 
            this._sightAnglePlusMenuCallback, this
        );
        this._sightAngleMinusMenuPanelItem = new ssr.MenuPanelItem(
            "  Angle-", 
            this._sightAngleMinusMenuCallback, this
        );
        this._sightSizeMenuPanelItem = new ssr.ToggleMenuPanelItem(
            [
                "  × Custom Size",
                "  ○ Custom Size"
            ], this._sightSizeMenuCallback, this
        );
        this._sightRectMenuPanelItem = new ssr.ToggleMenuPanelItem(
            [
                "  × Custom Rect",
                "  ○ Custom Rect"
            ], this._sightRectMenuCallback, this
        );
        this._dirtyDetectionPanelItem = new ssr.ToggleMenuPanelItem(
            [
                "  × Dirty Detection", 
                "  ○ Dirty Detection"
            ], this._dirtyDetectionMenuCallback, this
        );
        this._maskTextPanelItem = new ssr.TextPanelItem(
            "  --- LoSMask ---",
            cc.sys.isNative ? cc.MenuItemFont.getFontName(): cc.MenuItemFont.fontName(), 
            cc.sys.isNative ? cc.MenuItemFont.getFontSize(): cc.MenuItemFont.fontSize()
        );
        this._shadowTextPanelItem = new ssr.TextPanelItem(
            "  --- LoSShadow ---",
            cc.sys.isNative ? cc.MenuItemFont.getFontName(): cc.MenuItemFont.fontName(), 
            cc.sys.isNative ? cc.MenuItemFont.getFontSize(): cc.MenuItemFont.fontSize()
        );
        this._coreTextPanelItem = new ssr.TextPanelItem(
            "  --- LoSCore ---",
            cc.sys.isNative ? cc.MenuItemFont.getFontName(): cc.MenuItemFont.fontName(), 
            cc.sys.isNative ? cc.MenuItemFont.getFontSize(): cc.MenuItemFont.fontSize()
        );
        this._floatingMenu.addItems(
            this._coreTextPanelItem,
            this._sightRangeMenuPanelItem,
            this._sightRangePlusMenuPanelItem,
            this._sightRangeMinusMenuPanelItem,
            this._sightAnglePlusMenuPanelItem,
            this._sightAngleMinusMenuPanelItem,
            this._sightSizeMenuPanelItem,
            this._sightRectMenuPanelItem,
            this._dirtyDetectionPanelItem,
            //
            this._maskTextPanelItem,
            this._losMaskRenderMenuPanelItem,
            this._losSelfCullingMenuPanelItem,
            //
            this._shadowTextPanelItem,
            this._losShadowRenderMenuPanelItem,
            // this._losShadowDynamicRenderMenuPanelItem,
            // this._losShadowTextureRenderMenuPanelItem,
            // this._losShadowRadiusPlusMenuPanelItem,
            // this._losShadowRadiusMinusMenuPanelItem,
            //
            this._debugTextPanelItem,
            this._sightAreaRenderMenuPanelItem,
            this._sightLightRenderMenuPanelItem,
            this._sightRangeRenderMenuPanelItem,
            this._rayRenderMenuPanelItem,
            this._hitPointRenderMenuPanelItem,
            this._sightVertRenderMenuPanelItem,
            this._potentialBlockingEdgesRenderMenuPanelItem,
            this._blockingEdgesRenderMenuPanelItem,
            this._visibleEdgeRenderMenuPanelItem
        );
        this.addChild(this._floatingMenu, 99999);
    },
    _initMainLayer:function() {
        this._mainLayer = new cc.LayerColor(cc.color(0, 0, 0, 0), cc.winSize.width, cc.winSize.height);
        this.addChild(this._mainLayer, 1);
        //
        this._gridLine = new cc.Sprite(res.gridLine_png);
        this._gridLine.setPosition(this._mainLayer.width / 2, this._mainLayer.height / 2);
        this._gridLine.setOpacity(100);
        this._mainLayer.addChild(this._gridLine);
    },
    _initRobot:function() {
        this._robotObject = new RobotObject();
        this._robotObject.setPosition(cc.winSize.width / 2, cc.winSize.height / 2);
        this._mainLayer.addChild(this._robotObject, 2);
    },
    _initLoSComponentRender:function() {
        // ray
        this._losComponentRenderRay = new ssr.LoS.Component.RenderRay(this._robotObject.getLoSComponentCore());
        this._losComponentRenderRay.setup(ssr.LoS.Constant.RENDER_TRANSPARENT, 1, cc.color(255, 255, 0, 100));
        this._mainLayer.addChild(this._losComponentRenderRay);
        // hitPoint
        this._losComponentRenderHitPoint = new ssr.LoS.Component.RenderHitPoint(this._robotObject.getLoSComponentCore());
        this._losComponentRenderHitPoint.setup(ssr.LoS.Constant.RENDER_TRANSPARENT, 4, cc.color.GREEN);
        this._mainLayer.addChild(this._losComponentRenderHitPoint);
        // potentialBlockingEdge
        this._losComponentRenderPotentialBlockingEdge = new ssr.LoS.Component.RenderPotentialBlockingEdge(this._robotObject.getLoSComponentCore());
        this._losComponentRenderPotentialBlockingEdge.setup(ssr.LoS.Constant.RENDER_TRANSPARENT, 3, cc.color(237, 109, 0, 100));
        this._mainLayer.addChild(this._losComponentRenderPotentialBlockingEdge);
        // blockingEdge
        this._losComponentRenderBlockingEdge = new ssr.LoS.Component.RenderBlockingEdge(this._robotObject.getLoSComponentCore());
        this._losComponentRenderBlockingEdge.setup(ssr.LoS.Constant.RENDER_TRANSPARENT, 2, cc.color.BLUE);
        this._mainLayer.addChild(this._losComponentRenderBlockingEdge);
        // visibleEdge
        this._losComponentRenderVisibleEdge = new ssr.LoS.Component.RenderVisibleEdge(this._robotObject.getLoSComponentCore());
        this._losComponentRenderVisibleEdge.setup(ssr.LoS.Constant.RENDER_TRANSPARENT, 2, cc.color.YELLOW);
        this._mainLayer.addChild(this._losComponentRenderVisibleEdge);
        // sightVert
        this._losComponentRenderSightVert = new ssr.LoS.Component.RenderSightVert(this._robotObject.getLoSComponentCore());
        this._losComponentRenderSightVert.setup(ssr.LoS.Constant.RENDER_TRANSPARENT, 2, cc.color.RED);
        this._mainLayer.addChild(this._losComponentRenderSightVert);
        // sightRange
        this._losComponentRenderSightRange = new ssr.LoS.Component.RenderSightRange(this._robotObject.getLoSComponentCore());
        this._losComponentRenderSightRange.setup(cc.color(255, 0, 0, 20), ssr.LoS.Constant.RENDER_NO_BORDER, ssr.LoS.Constant.RENDER_TRANSPARENT);
        this._mainLayer.addChild(this._losComponentRenderSightRange);
        // sightArea
        this._losComponentRenderSightArea = new ssr.LoS.Component.RenderSightArea(this._robotObject.getLoSComponentCore());
        this._losComponentRenderSightArea.setup(cc.color(255, 255, 0, 100), ssr.LoS.Constant.RENDER_NO_BORDER, ssr.LoS.Constant.RENDER_TRANSPARENT);
        this._mainLayer.addChild(this._losComponentRenderSightArea);
        // sightLight
        this._losComponentRenderSightLight = new ssr.LoS.Component.RenderSightLight(this._robotObject.getLoSComponentCore());
        this._losComponentRenderSightLight.setup(cc.color(255, 200, 0, 200), ssr.LoS.Constant.RENDER_NO_BORDER, ssr.LoS.Constant.RENDER_TRANSPARENT);
        this._mainLayer.addChild(this._losComponentRenderSightLight);
    },
    _initKeyboard:function() {
        if(cc.sys.isNative || cc.sys.isMobile) {
            this.joyStickLayer = new JoyStickLayer();
            this.addChild(this.joyStickLayer, 999999999);
        }
        else {
            this._keyboardController = new ssr.KeyboardController(this);
            this.addChild(this._keyboardController);
        }
    },
    _initDebugDraw:function() {
        this._sightRayDebugLabel = new cc.LabelTTF("", cc.sys.isNative ? cc.MenuItemFont.getFontName(): cc.MenuItemFont.fontName(), cc.sys.isNative ? cc.MenuItemFont.getFontSize(): cc.MenuItemFont.fontSize());
        this._sightRayDebugLabel.setColor(TestLoSMapBase.DEBUG_COLOR_RAY);
        this._sightRayDebugLabel.setAnchorPoint(0, 0.5);
        this._sightRayDebugLabel.setPosition(this._rayRenderMenuPanelItem.getContentSize().width * 0.5, 0);
        this._rayRenderMenuPanelItem.addChild(this._sightRayDebugLabel, 0, "DebugLabel");

        this._hitPointDebugLabel = new cc.LabelTTF("", cc.sys.isNative ? cc.MenuItemFont.getFontName(): cc.MenuItemFont.fontName(), cc.sys.isNative ? cc.MenuItemFont.getFontSize(): cc.MenuItemFont.fontSize());
        this._hitPointDebugLabel.setColor(TestLoSMapBase.DEBUG_COLOR_HITPOINT);
        this._hitPointDebugLabel.setAnchorPoint(0, 0.5);
        this._hitPointDebugLabel.setPosition(this._hitPointRenderMenuPanelItem.getContentSize().width * 0.5, 0);
        this._hitPointRenderMenuPanelItem.addChild(this._hitPointDebugLabel, 0, "DebugLabel");

        this._potentialBlockingEdgeDebugLabel = new cc.LabelTTF("", cc.sys.isNative ? cc.MenuItemFont.getFontName(): cc.MenuItemFont.fontName(), cc.sys.isNative ? cc.MenuItemFont.getFontSize(): cc.MenuItemFont.fontSize());
        this._potentialBlockingEdgeDebugLabel.setColor(TestLoSMapBase.DEBUG_COLOR_POTENTIAL_BLOCKING_EDGE);
        this._potentialBlockingEdgeDebugLabel.setAnchorPoint(0, 0.5);
        this._potentialBlockingEdgeDebugLabel.setPosition(this._potentialBlockingEdgesRenderMenuPanelItem.getContentSize().width * 0.5, 0);
        this._potentialBlockingEdgesRenderMenuPanelItem.addChild(this._potentialBlockingEdgeDebugLabel, 0, "DebugLabel");

        this._blockingEdgeDebugLabel = new cc.LabelTTF("", cc.sys.isNative ? cc.MenuItemFont.getFontName(): cc.MenuItemFont.fontName(), cc.sys.isNative ? cc.MenuItemFont.getFontSize(): cc.MenuItemFont.fontSize());
        this._blockingEdgeDebugLabel.setColor(TestLoSMapBase.DEBUG_COLOR_BLOCKING_EDGE);
        this._blockingEdgeDebugLabel.setAnchorPoint(0, 0.5);
        this._blockingEdgeDebugLabel.setPosition(this._blockingEdgesRenderMenuPanelItem.getContentSize().width * 0.5, 0);
        this._blockingEdgesRenderMenuPanelItem.addChild(this._blockingEdgeDebugLabel, 0, "DebugLabel");

        this._visibleEdgeDebugLabel = new cc.LabelTTF("", cc.sys.isNative ? cc.MenuItemFont.getFontName(): cc.MenuItemFont.fontName(), cc.sys.isNative ? cc.MenuItemFont.getFontSize(): cc.MenuItemFont.fontSize());
        this._visibleEdgeDebugLabel.setColor(TestLoSMapBase.DEBUG_COLOR_VISIBLE_EDGE);
        this._visibleEdgeDebugLabel.setAnchorPoint(0, 0.5);
        this._visibleEdgeDebugLabel.setPosition(this._visibleEdgeRenderMenuPanelItem.getContentSize().width * 0.5, 0);
        this._visibleEdgeRenderMenuPanelItem.addChild(this._visibleEdgeDebugLabel, 0, "DebugLabel");

        this._sightVertDebugLabel = new cc.LabelTTF("", cc.sys.isNative ? cc.MenuItemFont.getFontName(): cc.MenuItemFont.fontName(), cc.sys.isNative ? cc.MenuItemFont.getFontSize(): cc.MenuItemFont.fontSize());
        this._sightVertDebugLabel.setColor(TestLoSMapBase.DEBUG_COLOR_VERT);
        this._sightVertDebugLabel.setAnchorPoint(0, 0.5);
        this._sightVertDebugLabel.setPosition(this._sightVertRenderMenuPanelItem.getContentSize().width * 0.5, 0);
        this._sightVertRenderMenuPanelItem.addChild(this._sightVertDebugLabel, 0, "DebugLabel");

        this._sightRangeDebugLabel = new cc.LabelTTF("", cc.sys.isNative ? cc.MenuItemFont.getFontName(): cc.MenuItemFont.fontName(), cc.sys.isNative ? cc.MenuItemFont.getFontSize(): cc.MenuItemFont.fontSize());
        this._sightRangeDebugLabel.setAnchorPoint(0, 0.5);
        this._sightRangeDebugLabel.setPosition(this._sightRangePlusMenuPanelItem.getContentSize().width * 0.5, 0);
        this._sightRangePlusMenuPanelItem.addChild(this._sightRangeDebugLabel, 0, "DebugLabel");

        this._sightAngleDebugLabel = new cc.LabelTTF("", cc.sys.isNative ? cc.MenuItemFont.getFontName(): cc.MenuItemFont.fontName(), cc.sys.isNative ? cc.MenuItemFont.getFontSize(): cc.MenuItemFont.fontSize());
        this._sightAngleDebugLabel.setAnchorPoint(0, 0.5);
        this._sightAngleDebugLabel.setPosition(this._sightAnglePlusMenuPanelItem.getContentSize().width * 0.5, 0);
        this._sightAnglePlusMenuPanelItem.addChild(this._sightAngleDebugLabel, 0, "DebugLabel");
    },
    _initLoSMask:function() {
        this._losMaskNode = new ssr.LoS.Component.Mask(TestLoSMapBase.DEBUG_LOS_MASK);
        this.addChild(this._losMaskNode, 99);
        this._losMaskNode.setVisible(false);
    },
    _processRobotMoveAndRotate:function(dt) {
        var moveDirection = 0;
        var rotationDelta = 0;
        var velocityScale = cc.p(1, 1);
        if (this._keyboardController) {
            var targetRotation = this._robotObject.getRotation();
            if (this._keyboardController.isKeyPressed(cc.KEY.up) || 
                this._keyboardController.isKeyPressed(cc.KEY.w)) {
                moveDirection = 1;
            }
            else if (this._keyboardController.isKeyPressed(cc.KEY.down) || 
                     this._keyboardController.isKeyPressed(cc.KEY.s)) {
                moveDirection = -1;
            }
            if (this._keyboardController.isKeyPressed(cc.KEY.left) || 
                this._keyboardController.isKeyPressed(cc.KEY.a)) {
                rotationDelta = -2;
            }
            else if (this._keyboardController.isKeyPressed(cc.KEY.right) || 
                     this._keyboardController.isKeyPressed(cc.KEY.d)) {
                rotationDelta = 2;
            }
        }
        else {
            if (this.joyStickLayer && this.joyStickLayer.isTriggered()) {
                rotationDelta = 0;
                if (this.joyStickLayer.getDegrees() != 0) {
                    this._robotObject.setRotation(-this.joyStickLayer.getDegrees());
                }
                moveDirection = 1;
                velocityScale = this.joyStickLayer.getVelocity();
            }
        }
        if (rotationDelta != 0) {
            this._robotObject.setRotation(targetRotation + rotationDelta);
        }
        if (moveDirection != 0) {
            var desiredPosition = cc.pAdd(
                this._robotObject.getPosition(), 
                this._robotObject.getDesiredDeltaPosition(moveDirection, velocityScale)
            );
            this._robotObject.setPosition(desiredPosition);
        }
    },
    _processRobotSight:function(dt) {
        var isUpdated = this._robotObject.updateSightNode(this._isForceLoSUpdate);
        if (isUpdated) {
            this._losComponentRenderSightArea.plot();
            this._losComponentRenderSightRange.plot();
            this._losComponentRenderRay.plot();
            this._losComponentRenderHitPoint.plot();
            this._losComponentRenderSightVert.plot();
            this._losComponentRenderPotentialBlockingEdge.plot();
            this._losComponentRenderBlockingEdge.plot();
            this._losComponentRenderVisibleEdge.plot();
            this._losComponentRenderSightLight.plot();

            if (this._losMaskNode.isVisible()) {
                this._losMaskNode.updateTarget(this._robotObject, this._isForceLoSUpdate);
            }

            var rayCount = this._robotObject.getLoSComponentCore().getRayCount();
            this._sightRayDebugLabel = this._rayRenderMenuPanelItem.getChildByName("DebugLabel");
            this._sightRayDebugLabel.setString(" (" + rayCount + ")");

            var hitPointCount = this._robotObject.getLoSComponentCore().getHitPointCount();
            this._hitPointDebugLabel = this._hitPointRenderMenuPanelItem.getChildByName("DebugLabel");
            this._hitPointDebugLabel.setString(" (" + hitPointCount + ")");

            var sightVertCount = this._robotObject.getLoSComponentCore().getSightAreaVertCount();
            this._sightVertDebugLabel = this._sightVertRenderMenuPanelItem.getChildByName("DebugLabel");
            this._sightVertDebugLabel.setString(" (" + sightVertCount + ")");

            var potentialBlockingEdgeCount = this._robotObject.getLoSComponentCore().getPotentialBlockingEdgeCount();
            this._potentialBlockingEdgeDebugLabel = this._potentialBlockingEdgesRenderMenuPanelItem.getChildByName("DebugLabel");
            this._potentialBlockingEdgeDebugLabel.setString(" (" + potentialBlockingEdgeCount + ")");

            var blockingEdgeCount = this._robotObject.getLoSComponentCore().getBlockingEdgeCount();
            this._blockingEdgeDebugLabel = this._blockingEdgesRenderMenuPanelItem.getChildByName("DebugLabel");
            this._blockingEdgeDebugLabel.setString(" (" + blockingEdgeCount + ")");

            var visibleEdgeCount = this._robotObject.getLoSComponentCore().getVisibleEdgeCount();
            this._visibleEdgeDebugLabel = this._visibleEdgeRenderMenuPanelItem.getChildByName("DebugLabel");
            this._visibleEdgeDebugLabel.setString(" (" + visibleEdgeCount + ")");
        }
        for (var i = this._shadows.length - 1; i >= 0; i--) {
            this._shadows[i].update();
        }
        this._isForceLoSUpdate = false;
    },
    update:function(dt) {
        this._processRobotMoveAndRotate(dt);
        this._processRobotSight(dt);
    },
    // menu callback
    _dirtyDetectionMenuCallback:function(sender, data) {
        if (sender.getSelectedIndex() == 0) {
            this.disableDirtyDetection();
        }
        else {
            this.enableDirtyDetection();
        }  
    },
    _sightRectMenuCallback:function(sender) {
        this._sightSizeMenuPanelItem._menuItem.setSelectedIndex(0);
        if (sender.getSelectedIndex() == 0) {
            this._robotObject.getLoSComponentCore().enableAutoGenerateBoundary();
        }
        else {
            // fixed custom sight rect quarter of the screen
            this._robotObject.getLoSComponentCore().setSightRect(cc.rect(cc.winSize.width / 4, cc.winSize.height / 4, cc.winSize.width / 2, cc.winSize.height / 2));
        }
    },
    _sightSizeMenuCallback:function(sender) {
        this._sightRectMenuPanelItem._menuItem.setSelectedIndex(0);
        if (sender.getSelectedIndex() == 0) {
            this._robotObject.getLoSComponentCore().enableAutoGenerateBoundary();
        }
        else {
            // custom sight size half of the screen
            this._robotObject.getLoSComponentCore().setSightSize(cc.winSize.width / 2, cc.winSize.height / 2);
        }
    },
    _losMaskRenderMenuCallback:function(sender, data) {
        if (sender.getSelectedIndex() == 0) {
            this.disableLoSMask();
        }
        else {
            this.enableLoSMask();
        }  
    },
    _losShadowRenderMenuCallback:function(sender, data) {
        if (sender.getSelectedIndex() == 0) {
            this.disableLoSShadow();
        }
        else {
            this.enableLoSShadow();
        }  
    },
    _losSelfCullingMenuCallback:function(sender, data) {
        if (sender.getSelectedIndex() == 0) {
            this.disableLoSSelfCulling();
        }
        else {
            this.enableLoSSelfCulling();
        }  
    },
    _sightAreaRenderMenuCallback:function(sender, data) {
        if (sender.getSelectedIndex() == 0) {
            this.disableSightArea();
        }
        else {
            this.enableSightArea();
        }  
    },
    _sightLightRenderMenuCallback:function(sender, data) {
        if (sender.getSelectedIndex() == 0) {
            this.disableSightLight();
        }
        else {
            this.enableSightLight();
        }  
    },
    _sightRangeRenderMenuCallback:function(sender, data) {
        if (sender.getSelectedIndex() == 0) {
            this.disableSightRangeRender();
        }
        else {
            this.enableSightRangeRender();
        }  
    },
    _rayRenderMenuCallback:function(sender, data) {
        if (sender.getSelectedIndex() == 0) {
            this.disableRayRender();
        }
        else {
            this.enableRayRender();
        }
    },
    _hitPointRenderMenuCallback:function(sender, data) {
        if (sender.getSelectedIndex() == 0) {
            this.disableHitPointRender()
        }
        else {
            this.enableHitPointRender();
        }
    },
    _sightVertRenderMenuCallback:function(sender, data) {
        if (sender.getSelectedIndex() == 0) {
            this.disableSightVertRender()
        }
        else {
            this.enableSightVertRender();
        }
    },
    _potentialBlockingEdgesRenderMenuCallback:function(sender, data) {
        if (sender.getSelectedIndex() == 0) {
            this.disablePotentialBlockingEdgesRender();
        }
        else {
            this.enablePotentialBlockingEdgesRender(); 
        }
    },
    _blockingEdgesRenderMenuCallback:function(sender, data) {
        if (sender.getSelectedIndex() == 0) {
            this.disableBlockingEdgesRender();
        }
        else {
            this.enableBlockingEdgesRender()   
        }
    },
    _visibleEdgeRenderMenuCallback:function(sender, data) {
        if (sender.getSelectedIndex() == 0) {
            this.disableVisibleEdgesRender();
        }
        else {
            this.enableVisibleEdgesRender();
        }
    },
    _sightRangeMenuCallback:function(sender, data) {
        if (sender.getSelectedIndex() == 0) {
            this.disableSightRange();
        }
        else {
            this.enableSightRange();
        }  
    },
    _sightRangePlusMenuCallback:function(sender, data) {
        this.sightRangePlus();
    },
    _sightRangeMinusMenuCallback:function(sender, data) {
        this.sightRangeMinus();
    },
    _sightAnglePlusMenuCallback:function(sender, data) {
        this.sightAnglePlus();
    },
    _sightAngleMinusMenuCallback:function(sender, data) {
        this.sightAngleMinus();
    },
    /*********************************** menu logic ***********************************/
    disableLoSMask:function() {
        this._isForceLoSUpdate = true;
        this._losMaskNode.setVisible(false);
    },
    enableLoSMask:function() {
        this._isForceLoSUpdate = true;
        this._losMaskNode.setVisible(true);
    },
    disableLoSShadow:function() {
        this._isForceLoSUpdate = true;
        var obstacles = this._robotObject.getLoSComponentCore().getObstacles();
        for (var i = 0; i < obstacles.length; i ++) {
            obstacles[i].getNode().removeAllChildren(true);
        }
        this._shadows = [];
    },
    enableLoSShadow:function() {
        this._isForceLoSUpdate = true;
        var obstacles = this._robotObject.getLoSComponentCore().getObstacles();
        for (var i = 0; i < obstacles.length; i ++) {
            var shadowComponent = new ssr.LoS.Component.Shadow(
                this._robotObject,
                obstacles[i].getNode(),
                {
                    "color": cc.color(0, 0, 0, 255),
                    "texture": "res/shadow.png",
                    "dynamic": true,
                    "scale": 2,
                }
            );
            obstacles[i].getNode().addChild(shadowComponent, -1);
            shadowComponent.setPosition(obstacles[i].getNode().width / 2, obstacles[i].getNode().height / 2);
            this._shadows.push(shadowComponent);
            shadowComponent.addCullingObstacles(obstacles);
        }
    },
    disableLoSSelfCulling:function() {
        this._isForceLoSUpdate = true;
        var obstacles = this._robotObject.getLoSComponentCore().getObstacles();
        for (var i = 0; i < obstacles.length; i ++) {
            obstacles[i].disableSelfCulling();
        }
    },
    enableLoSSelfCulling:function() {
        this._isForceLoSUpdate = true;
        var obstacles = this._robotObject.getLoSComponentCore().getObstacles();
        for (var i = 0; i < obstacles.length; i ++) {
            obstacles[i].enableSelfCulling();
        }
    },
    enableSightArea:function() {
        this._isForceLoSUpdate = true;
        this._losComponentRenderSightArea.enable();
    },
    disableSightArea:function() {
        this._isForceLoSUpdate = true;
        this._losComponentRenderSightArea.disable();
    },
    enableSightLight:function() {
        this._isForceLoSUpdate = true;
        this._losComponentRenderSightLight.enable();
    },
    disableSightLight:function() {
        this._isForceLoSUpdate = true;
        this._losComponentRenderSightLight.disable();
    },
    enableSightRangeRender:function() {
        this._isForceLoSUpdate = true;
        this._losComponentRenderSightRange.enable();
    },
    disableSightRangeRender:function() {
        this._isForceLoSUpdate = true;
        this._losComponentRenderSightRange.disable();
    },
    enableRayRender:function() {
        this._isForceLoSUpdate = true;
        this._losComponentRenderRay.enable();
    },
    disableRayRender:function() {
        this._isForceLoSUpdate = true;
        this._losComponentRenderRay.disable();
    },
    enableHitPointRender:function() {
        this._isForceLoSUpdate = true;
        this._losComponentRenderHitPoint.enable();
    },
    disableHitPointRender:function() {
        this._isForceLoSUpdate = true;
        this._losComponentRenderHitPoint.disable();
    },
    enableSightVertRender:function() {
        this._isForceLoSUpdate = true;
        this._losComponentRenderSightVert.enable();
    },
    disableSightVertRender:function() {
        this._isForceLoSUpdate = true;
        this._losComponentRenderSightVert.disable();
    },
    enablePotentialBlockingEdgesRender:function() {
        this._isForceLoSUpdate = true;
        this._losComponentRenderPotentialBlockingEdge.enable();
    },
    disablePotentialBlockingEdgesRender:function() {
        this._isForceLoSUpdate = true;
        this._losComponentRenderPotentialBlockingEdge.disable();
    },
    enableBlockingEdgesRender:function() {
        this._isForceLoSUpdate = true;
        this._losComponentRenderBlockingEdge.enable();
    },
    disableBlockingEdgesRender:function() {
        this._isForceLoSUpdate = true;
        this._losComponentRenderBlockingEdge.disable();
    },
    enableVisibleEdgesRender:function() {
        this._isForceLoSUpdate = true;
        this._losComponentRenderVisibleEdge.enable();
    },
    disableVisibleEdgesRender:function() {
        this._isForceLoSUpdate = true;
        this._losComponentRenderVisibleEdge.disable();
    },
    enableDirtyDetection:function() {
        if (this._robotObject) {
            var obstacles = this._robotObject.getLoSComponentCore().getObstacles();
            for (var i = 0; i < obstacles.length; i ++) {
                obstacles[i].enableDirtyDetection();
            }
        }
    },
    disableDirtyDetection:function() {
        if (this._robotObject) {
            var obstacles = this._robotObject.getLoSComponentCore().getObstacles();
            for (var i = 0; i < obstacles.length; i ++) {
                obstacles[i].disableDirtyDetection();
            }
        }
    },
    enableSightRange:function() {
        if (this._robotObject) {
            if (this._robotObject.getLoSComponentCore().getRadius() == -1) {
                this._robotObject.getLoSComponentCore().setRadius(32 * 4);
                this._losComponentRenderSightLight.setRadius(this._robotObject.getLoSComponentCore().getRadius() * 2);
                this._losComponentRenderSightLight.setSourceRadius(this._robotObject.getLoSComponentCore().getRadius() / 10);
                this._losComponentRenderSightLight.setIntensity(0.6);
            }
            this._isForceLoSUpdate = true;
        }
        this._sightRangePlusMenuPanelItem._menuItem.setEnabled(true);
        this._sightRangeMinusMenuPanelItem._menuItem.setEnabled(true);
        this._sightAnglePlusMenuPanelItem._menuItem.setEnabled(true);
        this._sightAngleMinusMenuPanelItem._menuItem.setEnabled(true);
        this._sightSizeMenuPanelItem._menuItem.setEnabled(false);
        this._sightRectMenuPanelItem._menuItem.setEnabled(false);

        this._sightRangeDebugLabel.setString(" (" + this._robotObject.getLoSComponentCore().getRadius() + ")");
        this._sightRangeDebugLabel.setColor(cc.color.WHITE);
        this._sightAngleDebugLabel.setString(" (" + this._robotObject.getLoSComponentCore().getCentralAngle() + ")");
        this._sightAngleDebugLabel.setColor(cc.color.WHITE);
    },
    disableSightRange:function() {
        if (this._robotObject) {
            this._robotObject.getLoSComponentCore().setCentralAngle(ssr.LoS.Constant.FULL_ANGLE);
            this._robotObject.getLoSComponentCore().setRadius(ssr.LoS.Constant.UNLIMITED_RANGE);
            this._losComponentRenderSightLight.setRadius(Math.sqrt(cc.winSize.width * cc.winSize.width, cc.winSize.height * cc.winSize.height) * 2);
            this._losComponentRenderSightLight.setSourceRadius(10);
            this._losComponentRenderSightLight.setIntensity(0.8);
            this._isForceLoSUpdate = true;
        }
        this._sightRangePlusMenuPanelItem._menuItem.setEnabled(false);
        this._sightRangeMinusMenuPanelItem._menuItem.setEnabled(false);
        this._sightAnglePlusMenuPanelItem._menuItem.setEnabled(false);
        this._sightAngleMinusMenuPanelItem._menuItem.setEnabled(false);
        this._sightSizeMenuPanelItem._menuItem.setEnabled(true);
        this._sightRectMenuPanelItem._menuItem.setEnabled(true);

        this._sightRangeDebugLabel.setString("N/A");
        this._sightRangeDebugLabel.setColor(cc.color.GRAY);
        this._sightAngleDebugLabel.setString("N/A");
        this._sightAngleDebugLabel.setColor(cc.color.GRAY);
    },
    sightRangeMinus:function() {
        if (this._robotObject) {
            var radius = this._robotObject.getLoSComponentCore().getRadius();
            if (radius <= 0) {
                return;
            }
            this._robotObject.getLoSComponentCore().setRadius(radius - 8);
            this._losComponentRenderSightLight.setRadius(this._robotObject.getLoSComponentCore().getRadius() * 2);
            this._losComponentRenderSightLight.setSourceRadius(this._robotObject.getLoSComponentCore().getRadius() / 10);
        }
        this._isForceLoSUpdate = true;
        this._sightRangeDebugLabel.setString(" (" + this._robotObject.getLoSComponentCore().getRadius() + ")");
    },
    sightRangePlus:function() {
        if (this._robotObject) {
            var radius = this._robotObject.getLoSComponentCore().getRadius();
            this._robotObject.getLoSComponentCore().setRadius(radius + 8);
            this._losComponentRenderSightLight.setRadius(this._robotObject.getLoSComponentCore().getRadius() * 2);
            this._losComponentRenderSightLight.setSourceRadius(this._robotObject.getLoSComponentCore().getRadius() / 10);
        }
        this._isForceLoSUpdate = true;
        this._sightRangeDebugLabel.setString(" (" + this._robotObject.getLoSComponentCore().getRadius() + ")");
    },
    sightAnglePlus:function() {
        if (this._robotObject) {
            var angle = this._robotObject.getLoSComponentCore().getCentralAngle();
            this._robotObject.getLoSComponentCore().setCentralAngle(angle + 2);
        }
        this._isForceLoSUpdate = true;
        this._sightAngleDebugLabel.setString(" (" + this._robotObject.getLoSComponentCore().getCentralAngle() + "°)");
    },
    sightAngleMinus:function() {
        if (this._robotObject) {
            var angle = this._robotObject.getLoSComponentCore().getCentralAngle();
            this._robotObject.getLoSComponentCore().setCentralAngle(angle - 2);
        }
        this._isForceLoSUpdate = true;
        this._sightAngleDebugLabel.setString(" (" + this._robotObject.getLoSComponentCore().getCentralAngle() + "°)");
    },
});

TestLoSMapBase.DEBUG_COLOR_RAY = cc.color(255, 255, 0, 100);
TestLoSMapBase.DEBUG_COLOR_HITPOINT = cc.color.GREEN;
TestLoSMapBase.DEBUG_COLOR_VERT = cc.color.RED;
TestLoSMapBase.DEBUG_COLOR_SIGHT_RANGE = cc.color(255, 0, 0, 20);
TestLoSMapBase.DEBUG_COLOR_POTENTIAL_BLOCKING_EDGE = cc.color(237, 109, 0, 100);
TestLoSMapBase.DEBUG_COLOR_BLOCKING_EDGE = cc.color.BLUE;
TestLoSMapBase.DEBUG_COLOR_VISIBLE_EDGE = cc.color.YELLOW;
TestLoSMapBase.DEBUG_COLOR_SIGHT = cc.color(255, 200, 0, 100);
TestLoSMapBase.DEBUG_LOS_MASK = cc.color(0, 0, 0, 200);
